const CFG = require('../config');
const FUN = require('../comm/func');
const tbDevice = require('../model/tb_device');
const tbLog = require('../model/tb_log');
const rCache = require('../model/redis_cache');
const timLib = require('../comm/time-lib');
const devManger = require('./devManger');

module.exports = class devConfig
{
  static _module_name_ = 'devConfig';
  static mqConn = null;
  static mqPub = null;

  // 拼凑主题
  static CombTopic(Func, DevId, Project = '0')
  {
    let DevTypeName = FUN.Hwid2TypeName(DevId);

    if (Func == 'var') {
      let DevIds = DevId.split('-');//拆分主从设备
      if(DevIds.length == 2) DevTypeName = FUN.Hwid2TypeName(DevIds[1]);
    }

    if (DevId[0] == '+') { DevTypeName = DevId.replace(/[+]/g,''); DevId='+'; }
    if (Project == '') Project = '0';

    switch (Func) {
      case 'tx':
      case 'rx':
      case 'var':
      case 'data':
        return `${Project}/${DevTypeName}/${Func}/${DevId}`;
      case 'cmd':
      case 'cmdres':
      case 'json':
      case 'upgrade':
      case 'log':
        return `${DevTypeName}/${Func}/${DevId}`;
      case 'online':
      case 'offline':
        return `+/${Func}`;
    }

    return 'null_node';
  }//end CombTopic

  //发送命令字符串
  static PubCmd2Dev(DevId, CmdStr, mqPub = ()=>{})
  {
    let topic = devConfig.CombTopic('cmd',DevId);

    if (mqPub == null) mqPub = this.mqPub;
    mqPub(topic, CmdStr);
    //console.log('>>>',topic,CmdStr);
  }

  //发送buf
  static PubBin2Dev(DevId, Buf, mqPub = null)
  {
    let topic = devConfig.CombTopic('upgrade', DevId);

    if (mqPub == null) mqPub = this.mqPub;
    mqPub(topic, Buf, {nolog:true});
    //console.log('>>>',topic,Buf);
  }

  //往设备的tx主题里发送数据报文
  static PubData2DevTx(DevId, Buf, mqPub = null)
  {
    let topic = devConfig.CombTopic('tx',DevId);

    if (mqPub == null) mqPub = this.mqPub;
    mqPub(topic, Buf);
    //console.log('>>>',topic,Buf);
  }

  //发送变量字符串给设备
  //会根据变量的brother进行组合topic
  static PubVar2Dev(DevId, VarStr, mqPub = null)
  {
    rCache.getAll(rCache.N_Config,DevId).then((dConf)=>{
      if (!dConf) return;//dev offline

      //if(!dConf.brother) dConf.brother=0;
      //if(!dConf.project) dConf.project='0';

      if (dConf.brother>DevId) DevId = DevId+'-'+dConf.brother;
      else DevId = dConf.brother+'-'+DevId;

      let VarTopic = devConfig.CombTopic('var', DevId, dConf.project);

      if (mqPub == null) mqPub = this.mqPub;
      mqPub(VarTopic, VarStr, {retain:true});
      //console.log('>>>',VarTopic,VarStr);
    })
  }

  //给设备发送config同步命令
  static SendConfigCmd(DevId)
  {
    //如果config_flag不存在，则新建赋值1，并设定发送config定时器
    //如果config_flag存在，则不处理
    //如果config_flag为2，表示配置完成
    rCache.exists(rCache.N_Config,DevId,'config_flag').then((has)=>{
      if(has!='0') return;
      rCache.set(rCache.N_Config,DevId,{'config_flag':1});

      setTimeout(()=>{//不定时发送config命令
        rCache.get(rCache.N_Config,DevId,'config_flag').then((res)=>{
          if(res!='2') devConfig.PubCmd2Dev(DevId,'config');//如果没有受到过配置包//获取板卡配置
        })
      },FUN.rand(4000,7000));

      setTimeout(()=>{//超时删除标志
        rCache.get(rCache.N_Config,DevId,'config_flag').then((res)=>{
          if(res!='2') rCache.hdel(rCache.N_Config,DevId,'config_flag');
        })
      },10000);
    })//end exists
  }

  //设备的数据库设置同步
  static DevDbSync(DevId,Rcd,Config)
  {
    let NeedReboot=false;

    //project设置
    if(Rcd.project!=Config.project) //将设置写入到数据库
    {
      tbDevice.updateDev(DevId, {project:Config.project}).then((affected)=>{
        if(affected) console.log('[%d] save project ok',DevId);
      })
    }

    //brother设置
    if(Rcd.brother!=Config.brother) //将设置写入到数据库
    {
      tbDevice.updateDev(DevId, {brother:Config.brother}).then((affected)=>{
        if(affected) console.log('[%d] save brother ok',DevId);
      })
    }

    if(NeedReboot)
    {
      setTimeout(()=>{
        devConfig.PubCmd2Dev(Rcd.hwid,'reset');//重启
      },1000);
    }
    else //不需要重启设备，说明设备已经配置好了
    {
      let obj={};
      obj.project = Rcd.project==null?'0':Rcd.project;
      obj.brother = Config.brother;
      obj.hwtype = Rcd.hwtype;
      rCache.set(rCache.N_Config,Rcd.hwid,obj);//记录到缓存，供mq发消息时拼接topic时使用
    }
  }//end DevConfig()

  //处理config信息包,resObj为板卡返回的config信息对象
  static ConfigResHandler(DevId,resObj)
  {
    rCache.getAll(rCache.N_Config,DevId).then((dConf)=>{
      if(!dConf) return;

      //如果校验码不对，发送stop命令
      let DevMode=dConf.mode;
      // if(resObj.auth==0 && DevMode==0)//取消了板卡的序列号授权
      // {
      //   rCache.set(rCache.N_Config,DevId,{'auth':'error'});
      //   devConfig.PubCmd2Dev(resObj.hwid,'stop');
      //   console.log('XXX STOP Dev',DevId,'for auth err.');
      //   return;
      // }

      //超过了授权日期，发送stop命令
      let NowCnt = timLib.NowStamp();
      let expire = dConf.expire;
      if(NowCnt > expire && DevMode==0)//设备过期了
      {
        rCache.set(rCache.N_Config,DevId,{'expire':'error'});
        devConfig.PubCmd2Dev(resObj.hwid,'stop');
        console.log('XXX STOP Dev',DevId,'for expire err.');
        return;
      }

      //如果rtc不对，发送rtc对时
      let NowRtc = parseInt(NowCnt/1000);
      //console.log('Now:',Now,Now-resObj['rtc']);
      if(NowRtc-resObj.rtc>30 || NowRtc-resObj.rtc<-30)
      {
        devConfig.PubCmd2Dev(DevId,'rtc '+NowRtc);
      }

      //根据数据库信息进行后续操作
      tbDevice.find(DevId).then((Record)=>{
        if(Record)
          devConfig.DevDbSync(DevId,Record,resObj);
      })
    })//end then
  }//end ConfigResHandler


  //处理cmd config的结果
  static JsonResHandler(Topic,JsonStr)
  {
    if(JsonStr.charAt(0)=='{' && JsonStr.charAt(JsonStr.length-1)=='}')
    {
      let resObj=JSON.parse(JsonStr);

      //处理包内容
      console.log('<<<',Topic,resObj.cmd);
      //console.log(resObj);

      //config回复包
      if(resObj.cmd=='config')
      {
        rCache.set(rCache.N_Config, resObj.hwid, {'config_flag':2}); // 存储已配置状态，config_flag=1发送过config命令，=2已经收到config
        tbLog.newDevLog(0, resObj.hwid, 3000, FUN.Hwid2TypeName(resObj.hwid)+' config', timLib.NowStamp()); // log记录
        this.ConfigResHandler(Topic.devId,resObj);
      }
      else if(resObj.cmd=='son')
      {
        devManger.Mq_SonConfig(Topic.devId,resObj.devs);
      }
      else if(resObj.cmd=='project')
      {
        rCache.set(rCache.N_Config,resObj.hwid,{'project':resObj.res});
        tbDevice.updateDev(resObj.hwid, {project:resObj.res}).then((affected)=>{
          if(affected) console.log('[%d] save project ok',resObj.hwid);
        })

        //更新网关下所有子节点
        let DevTypeName = FUN.Hwid2TypeName(resObj.hwid);
        if(DevTypeName == CFG.T_Gw)
          tbDevice.updateDevByParent(resObj.hwid, {project:resObj.res}).then((affected)=>{
            if(affected) console.log('[%d] save %d sons project ok',resObj.hwid,affected);
          })
      }
      else if(resObj.cmd=='brother')
      {
        rCache.set(rCache.N_Config,resObj.hwid,{'brother':resObj.res});
        tbDevice.updateDev(resObj.hwid, {brother:resObj.res}).then((affected)=>{
          if(affected) console.log('[%d] save brother ok',resObj.hwid);
        })
      }
    }
  }//end JsonResHandler

  //总的消息处理
  // Path.project=Name[0];
  // Path.devType=Name[1];
  // Path.func=Name[2];
  // Path.devId=Name[3];
  static mqMsgIn(Path, Payload, pkt)
  {
    if(Path.devType == CFG.T_Wpass || Path.devType == CFG.T_Gw) // wpass & allwin
    {
      if(Object.keys(Path).length == 3)
      {
        switch(Path.func)
        {
          case 'json':
            tbDevice.find(Path.devId).then((Record)=>{
              if(Record)//有本设备的记录
              {
                let dataBuf=Payload.toString().replace(/\x00/g,''); // 必须将buffer末尾的0x00去掉，否则导致JSON.parse出错
                this.JsonResHandler(Path,dataBuf);
              }
              else//无设备记录，直接stop
              {
                this.PubCmd2Dev(Path.devId,'stop');
                console.log('XXX STOP Dev',Path.devId,'for unreg.');
              }
            })//end find
            break;
        }
      }
      else if(Object.keys(Path).length == 2)
      {
        let info=Payload.toString().split(' ');
        if(Path.func=='online') devManger.Dev_Online(info[0],info[1]);
        else if(Path.func=='offline') devManger.Dev_Offline(info[0]);
      }
    }//end if wpass & allwin
    else if(Path.devType == CFG.T_Wdev)
    {
      if(Object.keys(Path).length == 2)
      {
        if(Path.func=='online') devManger.Mq_WDevOnline(Payload.toString());
        else if(Path.func=='offline') devManger.Mq_WDevOffline(Payload.toString());
      }
    }
    else if(Path.devType == CFG.T_Dtu)
    {
      if(Object.keys(Path).length == 2)
      {
        let info=Payload.toString().split(' ');
        if(Path.func=='online') devManger.Dev_Online(info[0],info[1]);
        else if(Path.func=='offline') devManger.Dev_Offline(info[0]);
      }
    }
  }





}//end module class
